using CommunityToolkit.Mvvm.ComponentModel;
using Sensor.UI.Models;
using Sensor.UI.PointClouds;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace Sensor.UI.ViewModels
{
    /// <summary>
    /// 点云视图模型
    /// </summary>
    public partial class PointCloudViewModel : ViewModelBase
    {
        #region 私有字段

        private readonly PointCloudInfo pointCloudInfo;
        private readonly SemaphoreSlim _updateSemaphore;
        private long _updateSequence;
        private readonly DispatcherTimer _resetTimer;

        #endregion

        #region 公共属性

        /// <summary>
        /// 点云相机信息
        /// </summary>
        [ObservableProperty]
        public PerspectiveCamera _pointCloudCamera = new();

        /// <summary>
        /// 线框点集合
        /// </summary>
        [ObservableProperty]
        public Point3DCollection _wireframePoints = [];

        /// <summary>
        /// 标记点集合
        /// </summary>
        [ObservableProperty]
        public Point3DCollection _markerPoints= [];

        /// <summary>
        /// 区域点集合
        /// </summary>
        [ObservableProperty]
        public Point3DCollection _regionPoints= [];

        /// <summary>
        /// 箭头模型
        /// </summary>
        [ObservableProperty]
        public Model3DGroup _arrows= new();

        #endregion

        #region 构造函数

        /// <summary>
        /// 初始化 PointCloudViewModel 类的新实例
        /// </summary>
        public PointCloudViewModel() 
        {
            // 加载模型并生成网格
            pointCloudInfo = PointCloudFactory.LoadModel(10, 20, 10, 100, 100, 4);
            LoadPointCloud();
            
            // 初始化并发控制
            _updateSemaphore = new SemaphoreSlim(1, 1);
            _updateSequence = 0;
            
            // 初始化重置定时器，500ms后自动还原模型
            _resetTimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(500)
            };
            _resetTimer.Tick += ResetTimer_Tick;
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 加载点云数据
        /// </summary>
        public void LoadPointCloud()
        {
            PointCloudCamera.Position = pointCloudInfo.CameraInfo.Position;
            PointCloudCamera.LookDirection = pointCloudInfo.CameraInfo.LookDirection;
            PointCloudCamera.UpDirection = pointCloudInfo.CameraInfo.UpDirection;

            WireframePoints.Clear();
            MarkerPoints.Clear();
            RegionPoints.Clear();
            Arrows.Children.Clear();

            // 使用集合初始化器直接创建新集合，避免中间列表
            WireframePoints = [.. pointCloudInfo.WireframePoints];
            MarkerPoints = [.. pointCloudInfo.ItemInfos.Select(itemInfo => itemInfo.Point)];
            RegionPoints = [.. pointCloudInfo.RegionInfos.SelectMany(regionInfo => regionInfo.ItemInfos.Select(itemInfo => itemInfo.Point))];
        }

        /// <summary>
        /// 异步更新点云数据，支持高并发有序执行
        /// </summary>
        /// <param name="sensorInfo">传感器信息</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>表示异步操作的任务</returns>
        public async Task UpdatePointCloudAsync(SensorInfo? sensorInfo, CancellationToken cancellationToken = default)
        {
            // 重置定时器，每次调用都重新开始计时
            _resetTimer.Stop();
            _resetTimer.Start();
            
            // 获取当前更新序列号
            long currentSequence = Interlocked.Increment(ref _updateSequence);
            
            // 等待获取信号量，确保同时只有一个更新操作在执行
            await _updateSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
            
            try
            {
                // 检查是否已被后续的更新请求取代
                if (_updateSequence != currentSequence)
                {
                    return;
                }

                // 执行实际的点云更新
                await UpdatePointCloudCoreAsync(sensorInfo, cancellationToken).ConfigureAwait(false);
                
                // 使用Dispatcher确保在UI线程上更新UI元素
                await Application.Current.Dispatcher.InvokeAsync(() => 
                {
                    UpdateUIElements();
                }, System.Windows.Threading.DispatcherPriority.Background, cancellationToken);
            }
            finally
            {
                _updateSemaphore.Release();
            }
        }

        /// <summary>
        /// 同步更新点云数据（为了保持向后兼容）
        /// </summary>
        /// <param name="sensorInfo">传感器信息</param>
        public void UpdatePointCloud(SensorInfo? sensorInfo)
        {
            // 使用同步上下文运行异步方法
            UpdatePointCloudAsync(sensorInfo).GetAwaiter().GetResult();
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 定时器Tick事件处理，500ms无更新则还原模型
        /// </summary>
        /// <param name="sender">事件发送者</param>
        /// <param name="e">事件参数</param>
        private async void ResetTimer_Tick(object? sender, EventArgs e)
        {
            // 停止定时器，避免重复触发
            _resetTimer.Stop();
            
            // 调用UpdatePointCloudCoreAsync(null)还原模型
            await UpdatePointCloudCoreAsync(null, CancellationToken.None).ConfigureAwait(false);
            
            // 在UI线程上更新UI元素
            await Application.Current.Dispatcher.InvokeAsync(() => 
            {
                UpdateUIElements();
            }, System.Windows.Threading.DispatcherPriority.Background);
        }

        /// <summary>
        /// 异步执行点云更新的核心逻辑
        /// </summary>
        /// <param name="sensorInfo">传感器信息</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>表示异步操作的任务</returns>
        private async Task UpdatePointCloudCoreAsync(SensorInfo? sensorInfo, CancellationToken cancellationToken)
        {
            // 如果sensorInfo为null，直接从pointCloudInfo刷新点云
            if (sensorInfo == null)
            {
                // 确保在UI线程上执行LoadPointCloud
                await Application.Current.Dispatcher.InvokeAsync(() => LoadPointCloud(), 
                    System.Windows.Threading.DispatcherPriority.Background, cancellationToken);
                return;
            }

            // 在后台线程执行计算密集型操作
            await Task.Run(() =>
            {
                // 预先计算所有需要的值，避免重复计算
                const double maxLengthValue = 10 * 10 + 10 * 10; // 最大可能长度的平方
                const double maxZForce = 25.0; // 传感器Z坐标的最大值
                const double maxDeformation = 4.0; // 最大变形深度
                const double oneMinusCosBase = 1.0; // 预计算基础值
                
                // 计算最大长度和缩放因子
                double maxLength = Math.Sqrt(maxLengthValue); // 最大可能长度（当X和Y都为最大值10时）
                double lengthScale = 2.5 / maxLength; // 预计算缩放因子

                // 创建临时集合存储计算结果
                var tempRegionPoints = new List<Point3D>();
                // 注意：不在后台线程创建Model3DGroup，是在UI线程中创建
                var tempArrowData = new List<(Point3D startPoint, Vector3D direction, double length)>();
                var regionInfos = pointCloudInfo.RegionInfos;
                var sensorItemInfos = sensorInfo.SensorItemInfos;

                // 预先创建传感器信息查找字典，提高查找效率
                var sensorInfoDict = new Dictionary<int, SensorItemInfo>(sensorItemInfos.Count);
                foreach (var item in sensorItemInfos)
                {
                    sensorInfoDict[item.Index] = item;
                }

                foreach (var regionInfo in regionInfos)
                {
                    // 检查取消请求
                    cancellationToken.ThrowIfCancellationRequested();
                    
                    // 使用字典查找替代LINQ的FirstOrDefault，提高性能
                    if (!sensorInfoDict.TryGetValue(regionInfo.Index, out var sensorItemInfo))
                    {
                        // 如果没有对应的传感器数据，使用原始点位置
                        foreach (var itemInfo in regionInfo.ItemInfos)
                        {
                            tempRegionPoints.Add(itemInfo.Point);
                        }
                        continue;
                    }

                    #region 箭头
                    // 计算箭头长度：sqrt(x^2 + y^2)
                    double x = sensorItemInfo.X;
                    double y = sensorItemInfo.Y;
                    double rawLength = Math.Sqrt(x * x + y * y);

                    // 归一化缩放箭头长度，使其在合理范围内（0.5到3.0之间）
                    double normalizedLength = 0.5 + rawLength * lengthScale; // 使用预计算的缩放因子

                    // 获取区域的法向量
                    Vector3D normalVector = regionInfo.RegionPoint.Vector;

                    // 创建与法向量垂直的箭头方向向量
                    Vector3D arrowDirection = Math.Abs(normalVector.Y) > 0.9 
                        ? new Vector3D(0, 0, 1) 
                        : new Vector3D(0, 1, 0);

                    // 计算与法向量垂直的方向向量
                    arrowDirection = Vector3D.CrossProduct(normalVector, arrowDirection);
                    arrowDirection.Normalize();

                    // 根据传感器数据调整箭头方向
                    double angle = Math.Atan2(x, y);

                    // 创建旋转矩阵，绕法向量旋转
                    var rotationAxis = normalVector;
                    var cosAngle = Math.Cos(angle);
                    var sinAngle = Math.Sin(angle);
                    var oneMinusCos = oneMinusCosBase - cosAngle;

                    var axisX = rotationAxis.X;
                    var axisY = rotationAxis.Y;
                    var axisZ = rotationAxis.Z;

                    // 罗德里格斯旋转公式
                    Vector3D rotatedDirection = new(
                        (cosAngle + axisX * axisX * oneMinusCos) * arrowDirection.X +
                        (axisX * axisY * oneMinusCos - axisZ * sinAngle) * arrowDirection.Y +
                        (axisX * axisZ * oneMinusCos + axisY * sinAngle) * arrowDirection.Z,
                        (axisY * axisX * oneMinusCos + axisZ * sinAngle) * arrowDirection.X +
                        (cosAngle + axisY * axisY * oneMinusCos) * arrowDirection.Y +
                        (axisY * axisZ * oneMinusCos - axisX * sinAngle) * arrowDirection.Z,
                        (axisZ * axisX * oneMinusCos - axisY * sinAngle) * arrowDirection.X +
                        (axisZ * axisY * oneMinusCos + axisX * sinAngle) * arrowDirection.Y +
                        (cosAngle + axisZ * axisZ * oneMinusCos) * arrowDirection.Z
                    );

                    // 存储箭头数据，而不是直接创建箭头模型
                    tempArrowData.Add((
                        regionInfo.RegionPoint.Point,
                        rotatedDirection,
                        normalizedLength
                    ));
                    #endregion

                    #region 力场凹陷
                    // 预计算一些值，避免在循环中重复计算
                    double zForce = sensorItemInfo.Z;
                    double zForceNormalized = Math.Abs(zForce) / maxZForce;
                    double forceDirection = Math.Sign(zForce);
                    double distanceThreshold = regionInfo.DistanceThreshold;
                    double sqrtZForceNormalized = Math.Sqrt(zForceNormalized);

                    // 对区域内的每个点应用力场凹陷效果
                    foreach (var itemInfo in regionInfo.ItemInfos)
                    {
                        // 检查取消请求
                        cancellationToken.ThrowIfCancellationRequested();
                        
                        // 计算点到区域中心的距离
                        double distanceToCenter = itemInfo.Distance;

                        // 计算距离衰减因子：距离越大，力的影响越小
                        // 使用更平缓的高斯函数实现平滑的距离衰减
                        double distanceRatio = distanceToCenter / distanceThreshold;
                        double distanceAttenuation = Math.Exp(-2.0 * Math.Pow(distanceRatio, 1.5));
                        distanceAttenuation = Math.Clamp(distanceAttenuation, 0, 1); // 限制在[0,1]范围内

                        // 综合Z力大小和距离衰减，计算最终凹陷强度
                        // 使用平方根函数使力的影响更加平滑
                        double finalInfluence = sqrtZForceNormalized * distanceAttenuation;

                        // 使用点自身的法向量（Vector属性）作为变形方向
                        // 根据力的方向决定是凹陷还是凸起
                        Vector3D deformationDirection = forceDirection > 0 ? -itemInfo.Vector : itemInfo.Vector;
                        deformationDirection.Normalize();

                        // 计算变形偏移量（强度乘以方向）
                        Vector3D deformationOffset = deformationDirection * (finalInfluence * maxDeformation);

                        // 应用变形效果，创建新的点位置
                        Point3D originalPoint = itemInfo.Point;
                        Point3D deformedPoint = new(
                            originalPoint.X + deformationOffset.X,
                            originalPoint.Y + deformationOffset.Y,
                            originalPoint.Z + deformationOffset.Z
                        );

                        // 添加到临时集合
                        tempRegionPoints.Add(deformedPoint);
                    }
                    #endregion
                }

                // 将计算结果存储到临时变量，稍后在UI线程中更新
                _tempRegionPoints = tempRegionPoints;
                _tempArrowData = tempArrowData;
            }, cancellationToken).ConfigureAwait(false);
        }

        /// <summary>
        /// 在UI线程上更新UI元素
        /// </summary>
        private void UpdateUIElements()
        {
            // 创建新的集合和对象，原子性地替换UI元素，避免部分更新导致的问题
            var newRegionPoints = new Point3DCollection();
            var newArrows = new Model3DGroup();

            // 更新UI元素
            if (_tempRegionPoints != null)
            {
                foreach (var point in _tempRegionPoints)
                {
                    newRegionPoints.Add(point);
                }
            }

            // 在UI线程上创建箭头模型
            if (_tempArrowData != null)
            {
                foreach (var (startPoint, direction, length) in _tempArrowData)
                {
                    var arrow = ArrowFactory.CreateArrow(
                        startPoint,
                        direction,
                        length
                    );
                    newArrows.Children.Add(arrow);
                }
            }

            // 原子性地替换UI元素
            RegionPoints = newRegionPoints;
            Arrows = newArrows;
        }

        #endregion

        #region 资源释放

        /// <summary>
        /// 释放资源
        /// 重写基类的Dispose方法，释放PointCloudViewModel特有的资源
        /// </summary>
        /// <param name="disposing">指示是否正在释放托管资源</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _resetTimer?.Stop();
                _updateSemaphore?.Dispose();
            }
            
            // 调用基类的Dispose方法
            base.Dispose(disposing);
        }

        #endregion

        #region 临时字段

        // 用于在后台线程和UI线程之间传递数据
        private List<Point3D>? _tempRegionPoints;
        private List<(Point3D startPoint, Vector3D direction, double length)>? _tempArrowData;

        #endregion
    }
}

